package com.zzl.alibaba.intelligentvoice.longtext.restful;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * description: 使用restful的方式合成长文本语音
 * @author 朱正磊
 * @date 2022-01-14 14:11:04
 */
public class SpeechLongSynthesizerRestfulDemo {

    private static Logger logger = LoggerFactory.getLogger(SpeechLongSynthesizerRestfulDemo.class);

    private String accessToken;

    private String appKey;

    /**
     * description: 构造函数
     * @author 朱正磊
     * @date 2022-01-14 14:21:23
     * @param appKey 项目appKey
     * @param accessToken AccessToken
     */
    public SpeechLongSynthesizerRestfulDemo(String appKey, String accessToken) {
        this.appKey = appKey;
        this.accessToken = accessToken;
    }

    /**
     * description: 发送POST请求合成长文本语音
     * @author 朱正磊
     * @date 2022-01-14 14:22:27
     * @param text 长文本内容
     * @param format 音频编码格式，比如mp3、wav等等
     * @param sampleRate 音频采样率，支持16000Hz和8000Hz，默认是16000Hz。
     * @param voice 发音人
     */
    public void processPOSTRequest(String text, String format, Integer sampleRate, String voice) {
        String url = "https://nls-gateway.cn-shanghai.aliyuncs.com/rest/v1/tts/async";
        // 拼接HTTP Post请求的消息体内容。
        JSONObject context = new JSONObject();
        // device_id设置，可以设置为自定义字符串或者设备信息id。
        context.put("device_id", "my_device_id");
        JSONObject header = new JSONObject();
        // 设置你的appkey。
        header.put("appkey", appKey);
        // 设置你的token。
        header.put("token", accessToken);
        // voice 发音人，可选，默认是xiaoyun。
        // volume 音量，范围是0~100，可选，默认50。
        // speech_rate 语速，范围是-500~500，可选，默认是0。
        // pitch_rate 语调，范围是-500~500，可选，默认是0。
        JSONObject tts = new JSONObject();
        tts.put("text", text);
        // 设置发音人。
        tts.put("voice", voice);
        // 设置编码格式。
        tts.put("format", format);
        // 设置采样率。
        tts.put("sample_rate", sampleRate);
        // 设置声音大小，可选。
        //tts.put("volume", 100);
        // 设置语速，可选。
        //tts.put("speech_rate", 200);
        // 长文本tts restful接口支持句级时间戳，默认为false。
        tts.put("enable_subtitle", true);
        JSONObject payload = new JSONObject();
        // 可选，是否设置回调。如果设置，则服务端在完成长文本语音合成之后回调用户此处设置的回调接口，将请求状态推送给用户侧。
        payload.put("enable_notify", false);
        payload.put("notify_url", "http://123.com");
        payload.put("tts_request", tts);
        JSONObject json = new JSONObject();
        json.put("context", context);
        json.put("header", header);
        json.put("payload", payload);
        String bodyContent = json.toJSONString();
        logger.info("POST Body Content: " + bodyContent);
        // 发起请求
        RequestBody reqBody = RequestBody.create(MediaType.parse("application/json"), bodyContent);
        Request request = new Request.Builder()
                .url(url)
                .header("Content-Type", "application/json")
                .post(reqBody)
                .build();
        try {
            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            String contentType = response.header("Content-Type");
            System.out.println("contentType = " + contentType);
            // 获取结果，并根据返回进一步进行处理。
            assert response.body() != null;
            String result = response.body().string();
            response.close();
            System.out.println("result = " + result);
            JSONObject resultJson = JSON.parseObject(result);
            if (resultJson.containsKey("error_code") && resultJson.getIntValue("error_code") == 20000000) {
                logger.info("Request Success! task_id = " + resultJson.getJSONObject("data").getString("task_id"));
                String task_id = resultJson.getJSONObject("data").getString("task_id");
                String request_id = resultJson.getString("request_id");
                /// 可选：轮询检查服务端的合成状态，该轮询操作非必须，如果设置了回调url，则服务端会在合成完成后主动回调。
                waitLoop4Complete(url, appKey, accessToken, task_id, request_id);
            } else {
                logger.error("Request Error: status=" + resultJson.getIntValue("status")
                        + ", error_code=" + resultJson.getIntValue("error_code")
                        + ", error_message=" + resultJson.getString("error_message"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * description: 根据特定信息轮询检查某个请求在服务端的合成状态，
     *              轮询操作非必须，如果设置了回调url，则服务端会在合成完成后主动回调。
     * @author 朱正磊
     * @date 2022-01-14 14:32:06
     * @param url 接口url地址
     * @param appkey 项目appKey
     * @param token AccessToken
     * @param task_id 任务id
     * @param request_id 请求id
     */
    private void waitLoop4Complete(String url, String appkey, String token, String task_id, String request_id) {
        String fullUrl = url + "?appkey=" + appkey + "&task_id=" + task_id + "&token=" + token + "&request_id=" + request_id;
        System.out.println("query url = " + fullUrl);
        while (true) {
            Request request = new Request.Builder().url(fullUrl).get().build();
            try {
                OkHttpClient client = new OkHttpClient();
                Response response = client.newCall(request).execute();
                assert response.body() != null;
                String result = response.body().string();
                response.close();
                System.out.println("waitLoop4Complete = " + result);
                JSONObject resultJson = JSON.parseObject(result);
                if (resultJson.containsKey("error_code")
                        && resultJson.getIntValue("error_code") == 20000000
                        && resultJson.containsKey("data")
                        && resultJson.getJSONObject("data").getString("audio_address") != null) {
                    logger.info("Tts Finished! task_id = " + resultJson.getJSONObject("data").getString("task_id"));
                    logger.info("Tts Finished! audio_address = " + resultJson.getJSONObject("data").getString("audio_address"));
                    break;
                } else {
                    logger.info("Tts Queuing...");
                }
                // 每隔10秒钟轮询一次状态。
                Thread.sleep(10000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * description: 主程序执行入口
     * @author 朱正磊
     * @date 2022-01-14 14:51:41
     * @param args 参数
     */
    public static void main(String[] args) {
        if (args.length < 2) {
            System.err.println("SpeechLongSynthesizerRestfulDemo need params: <token> <app-key>");
            System.exit(-1);
        }
        String token = args[0];
        String appKey = args[1];
        SpeechLongSynthesizerRestfulDemo demo = new SpeechLongSynthesizerRestfulDemo(appKey, token);
        demo.processPOSTRequest("text", "format", 16000, "voice");
    }

}
